<!DOCTYPE html>
<html lang="zh-CH" >
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="author" content="" />
	
	
	
	<title>Unity官方文档翻译之使用本地 assetbundles ｜ zansimple</title>
	
    
    
    <meta name="description" content="使用本地 assetbundles 在 Unity5 中，有四种不同的方式来加载 assetbundles ,他们的方法是根据被加载的平台来使用不同的压缩方法（未压缩，LZMA , LZ4 ）创建assetbundle ， 我们要处理的四个 APIs 是：
 AssetBundle.LoadFromMemoryAsync AssetBundle.LoadFromFile WWW.LoadfromCacheOrDownload UnityWebRequest’s DownloadHandlerAssetBundle ( Unity 5.3 or 更新版本)  AssetBundle.LoadFromMemoryAsync 这个函数的参数是含有 assetbundle 数据的字节数组，如果你愿意的话，你也可以选择传入一个 CRC 值,如果 assetbundle 包是用 lzma 算法压缩的，当它加载时会被解压缩。如果是用 LZ4 算法压缩的 assetbundle 包，那么直接加载压缩状态的包。 这有个如何使用这个方法的例子：
using UnityEngine;using System.Collections;using System.IO;public class Example : MonoBehaviour{IEnumerator LoadFromMemoryAsync(string path){AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));yield return createRequest;AssetBundle bundle = createRequest.assetBundle;var prefab = bundle." />
    

    

	
    
    <link rel="shortcut icon" href="https://lenzan.github.io/images/favicon.ico" />

    <link rel="stylesheet" type="text/css" media="screen" href="https://lenzan.github.io/css/normalize.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.0/animate.min.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://lenzan.github.io/css/zozo.css" />
	<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://lenzan.github.io/css/highlight.css" />

    
    
</head>

<body>
    <div class="main animate__animated animate__fadeInDown">
        <div class="nav_container animated fadeInDown">
    <div class="site_nav" id="site_nav">
        <ul>
            
            <li>
                <a href="/">首页</a>
            </li>
            
            <li>
                <a href="/">unity</a>
            </li>
            
            <li>
                <a href="/">归档</a>
            </li>
            
            <li>
                <a href="/">关于</a>
            </li>
            
        </ul>
    </div>
    <div class="menu_icon">
        <a id="menu_icon"><i class="ri-menu-line"></i></a>
    </div>
</div>
        <div class="header animated fadeInDown">
    <div class="site_title_container">
        <div class="site_title">
            <h1>
                <a href="https://lenzan.github.io/">
                    <span>zansimple</span>
                    <img src="https://lenzan.github.io/images/logo.svg" />
                </a>
            </h1>
        </div>
        <div class="description">
            <p class="sub_title">专注于Unity虚拟现实开发，游戏开发</p>
            <div class="my_socials">
                
                <a href="https://lenzan.github.io/index.xml" type="application/rss+xml" title="rss" target="_blank"><i
                        class="ri-rss-fill"></i></a>
            </div>
        </div>
    </div>
</div>
        <div class="content">
            <div class="post_page">
                <div class="post animate__animated animate__fadeInDown">
                    <div class="post_title post_detail_title">
                        <h2><a href='/posts/assetbundle/using-assetbundles-natively/'>Unity官方文档翻译之使用本地 assetbundles</a></h2>
                        <span class="date">2018.05.28</span>
                    </div>
                    <div class="post_content markdown"><h3 id="使用本地-assetbundles">使用本地 assetbundles</h3>
<p>在 Unity5 中，有四种不同的方式来加载 assetbundles ,他们的方法是根据被加载的平台来使用不同的压缩方法（未压缩，LZMA , LZ4 ）创建assetbundle ，
我们要处理的四个 APIs 是：</p>
<ul>
<li>AssetBundle.LoadFromMemoryAsync</li>
<li>AssetBundle.LoadFromFile</li>
<li>WWW.LoadfromCacheOrDownload</li>
<li>UnityWebRequest’s DownloadHandlerAssetBundle ( Unity 5.3 or 更新版本)</li>
</ul>
<h4 id="assetbundleloadfrommemoryasync">AssetBundle.LoadFromMemoryAsync</h4>
<p>这个函数的参数是含有 assetbundle 数据的字节数组，如果你愿意的话，你也可以选择传入一个 CRC 值,如果 assetbundle 包是用 lzma 算法压缩的，当它加载时会被解压缩。如果是用 LZ4 算法压缩的 assetbundle 包，那么直接加载压缩状态的包。
这有个如何使用这个方法的例子：</p>
<pre><code>using UnityEngine;
using System.Collections;
using System.IO;

public class Example : MonoBehaviour
{
    IEnumerator LoadFromMemoryAsync(string path)
    {
        AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
        yield return createRequest;
        AssetBundle bundle = createRequest.assetBundle;
        var prefab = bundle.LoadAsset&lt;GameObject&gt;(&quot;MyObject&quot;);
        Instantiate(prefab);
    }
}
</code></pre>
<p>然而，这并不是使用 LoadFromMemoryAsync 的唯一策略，File.ReadAllBytes（path）可以用任何想要获得字节数组的过程来替换</p>
<h4 id="assetbundleloadfromfile">AssetBundle.LoadFromFile</h4>
<p>这个 API 在本地加载未压缩的 bundles 的时候非常的高效。LoadFromFile 这个方法会直接从磁盘中加载，如果这个包是未压缩或者用 LZ4 算法压缩的 bundles。用这个方法加载一个用 LZMA 压缩的 bundles ,在加载到内存之前，先要将其解压缩。
一个如何使用 LoadFromFile 的例子：</p>
<pre><code>public class LoadFromFileExample extends MonoBehaviour {
    void Start() {
        var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, &quot;myassetBundle&quot;));
        if (myLoadedAssetBundle == null) {
            Debug.Log(&quot;Failed to load AssetBundle!&quot;);
            return;
        }
        var prefab = myLoadedAssetBundle.LoadAsset.&lt;GameObject&gt;(&quot;MyObject&quot;);
        Instantiate(prefab);
    }
}
</code></pre>
<p>注意：在安卓设备上，用 unity5.3 或者更早版本使用这个 api 在从 Streaming Assets 路径下加载 bundles 时会报错，因为这条路径的内容将驻留在压缩的 .jar 文件中。在 Unity5.4 及会更高版本可以很好的使用这个方法。</p>
<h4 id="wwwloadfromcacheordownload">WWW.LoadFromCacheOrDownload</h4>
<p><strong>这个API已经被启用（你可以使用UnityWebRequest）</strong>
这个 API 对于从远程服务器下载 assetbundle 或加载本地的 assetbundle 非常有用。它是 UnityWebRequest API 的旧版本，不太理想的版本。从远程服务器加载一个 AssetBundle 将自动缓存 AssetBundle 。如果 AssetBundle 被压缩，一个线程将被启动，解压缩并且将其写入缓存。一旦 bundle 被解压和缓存，它就会像 AssetBundle.LoadFromFile 一样载入。
如何使用 LoadFromCacheOrDownload 的一个例子：</p>
<pre><code>using UnityEngine;
using System.Collections;
public class LoadFromCacheOrDownloadExample : MonoBehaviour
{
    IEnumerator Start ()
    {
        while (!Caching.ready)
                yield return null;

        var www = WWW.LoadFromCacheOrDownload(&quot;http://myserver.com/myassetBundle&quot;, 5);
        yield return www;
        if(!string.IsNullOrEmpty(www.error))
        {
            Debug.Log(www.error);
            yield return;
        }
        var myLoadedAssetBundle = www.assetBundle;

        var asset = myLoadedAssetBundle.mainAsset;
    }
}
</code></pre>
<p>由于考虑到在 WWW 对象中缓存 AssetBundle 的字节的内存开销，建议所有使用 WWW 的开发人员。LoadFromCacheOrDownload 确保他们的assetbundle 很小——最多只有几兆字节。还建议在有限内存平台上运行的开发人员，比如移动设备，确保他们的代码每次只下载一个 AssetBundle ，以避免内存峰值。如果缓存文件夹没有任何空间来缓存额外的文件，那么 LoadFromCacheOrDownload 将会从缓存中迭代地删除最近使用的AssetBundle ，直到有足够的空间来储存新的 AssetBundle 。如果空间不可能使用（因为硬盘已经满了，或者缓存中的所有文件都在使用中），LoadFromCacheOrDownload（） 将绕过缓存，将文件传输到内存中。
为了强制 LoadFromCacheOrDownload 的下载版本参数（第二个参数）需要被改变。如果传递给函数的版本与当前缓存的 AssetBundle 的版本相匹配，那么 AssetBundle 只会从缓存中加载。</p>
<h4 id="unitywebrequest">UnityWebRequest</h4>
<p>UnityWebRequest 有一个专门的 API 调用来处理 assetbundle 。首先，您需要使用 UnityWebRequest.GetAssetBundle() 来创建您的 web 请求。返回请求后，将请求对象传递到 DownloadHandlerAssetBundle.GetContent（UnityWebRequest）。这个 GetContent 调用会返回你的AssetBundle 对象。
下载完成之后，还可以在 DownloadHandlerAssetBundle 类上使用 assetBundle 属性，这就和使用 AssetBundle.LoadFromFile 加载assetbundle 是一样的。
下面是一个如何加载包含两个 gameobject 并实例化它们的 AssetBundle 的示例。要开始这个过程，我们只需要调用 StartCoroutine（InstantiateObject()）;</p>
<pre><code>IEnumerator InstantiateObject()
{
    string uri = &quot;file:///&quot; + Application.dataPath + &quot;/AssetBundles/&quot; + assetBundleName;       
    UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
    yield return request.Send();
    AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
    GameObject cube = bundle.LoadAsset&lt;GameObject&gt;(&quot;Cube&quot;);
    GameObject sprite = bundle.LoadAsset&lt;GameObject&gt;(&quot;Sprite&quot;);
    Instantiate(cube);
    Instantiate(sprite);
}
</code></pre>
<p>使用 UnityWebRequest 的优势在于，它允许开发者以更灵活的方式处理下载的数据，并可能消除不必要的内存使用。这个比 UnityEngine.WWW 更超前，更推荐使用。</p>
<h5 id="loading-assets-from-assetbundles">Loading Assets from AssetBundles</h5>
<p>现在您已经成功地下载了您的 AssetBundle ，现在是时候加载一些资产了。
通用代码片段:</p>
<pre><code>T objectFromBundle = bundleObject.LoadAsset&lt;T&gt;(assetName);
</code></pre>
<p>T是你想要加载的资产类型。
在决定如何加载资产时，有几个选项我们有 LoadAsset、LoadAllAsset 和它们的 Async 对等物，分别是 LoadAssetAsync 和LoadAllAssetsAsync 。
这就是如何同步地从 assetbundle 中加载资产：
加载一个单独的游戏对象：</p>
<pre><code>GameObject gameObject = loadedAssetBundle.LoadAsset&lt;GameObject&gt;(assetName);
</code></pre>
<p>加载所有的游戏对象：</p>
<pre><code>Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();
</code></pre>
<p>现在，当先前显示的方法返回您正在加载的对象的类型或对象数组时，异步方法返回一个 AssetBundleRequest ，在访问资产之前，您需要等待这个操作完成。加载一个资产:</p>
<pre><code>AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync&lt;GameObject&gt;(assetName);
yield return request;
var loadedAsset = request.asset;
</code></pre>
<p>和</p>
<pre><code>AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request;
var loadedAssets = request.allAssets;
</code></pre>
<p>一旦你把你的资产加载了，你可以像在 Unity 中使用任何对象一样使用加载的对象。</p>
<h5 id="loading-assetbundle-manifests">Loading AssetBundle Manifests</h5>
<p>加载AssetBundle清单可能非常有用。特别是在处理 AssetBundle 依赖项时。要获得一个可用的 AssetBundleManifest 对象，您需要加载额外的AssetBundle （它的名称与它所在的文件夹相同），并从中加载一个 AssetBundleManifest 的对象。
从 AssetBundle 中加载 manifest 完全和从中加载其他资源一样：</p>
<pre><code>AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset&lt;AssetBundleManifest&gt;(&quot;AssetBundleManifest&quot;);
</code></pre>
<p>现在您可以通过上面例子中的 manifest 对象访问 AssetBundleManifest API 调用。在这里，您可以使用 manifest 来获得关于您构建的assetbundle 的信息。这些信息包括依赖数据、hash 数据和 assetbundle 的变量数据。
请记住在前面的部分中，当我们讨论 AssetBundle 依赖关系时，如果一个 bundles 对另一个 bundles 有依赖关系，那么这些 bundle 在加载原始bundles中的任何资产之前都需要加载。Manifest 可以找到可能的加载依赖项。比方说，我们想要加载名为 &ldquo;AssetBundle&rdquo; 的 assetBundle 的所有依赖项。</p>
<pre><code>AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset&lt;AssetBundleManifest&gt;(&quot;AssetBundleManifest&quot;);
string[] dependencies = manifest.GetAllDependencies(&quot;assetBundle&quot;); //Pass the name of the bundle you want the dependencies for.
foreach(string dependency in dependencies)
{
    AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}
</code></pre>
<p>现在您已经加载了 AssetBundle、AssetBundle 的依赖，现在是讨论管理所有这些加载的 AssetBundle 的时候了。</p>
<h4 id="managing-loaded-assetbundles">Managing Loaded AssetBundles</h4>
<p>当从活动场景中删除对象时，Unity 不会自动卸载对象。资产清理是在特定的时间触发的，它也可以手动触发。
重要的是要知道何时加载和卸载 AssetBundle 。不恰当地卸载一个 AssetBundle 会导致重复对象错误，或者其他不可预知的错误，比如缺少纹理。
关于 AssetBundle 管理的最重要的事情是什么时候调用 AssetBundle.Unload(bool) ; 。如果你要把 true 或 false 传递给函数调用.Unload 是一个非静态的方法，它将卸载你的 AssetBundle 。这个 API 卸载被调用的 AssetBundle 的头信息。该参数表明是否也卸载从这个AssetBundle 中实例化的所有对象。AssetBundle.Unload(true) 卸载从 AssetBundle 中加载的所有 GameObjects （及其依赖项）。这不包括复制的 GameObjects （比如实例化的 gameobject ），因为它们不再属于 AssetBundle 。当这种情况发生时，从 AssetBundle 中加载的纹理（仍然属于它）从场景中的 gameobject 中消失，Unity 将它们视为缺失的纹理。
让我们假设材质M是从 AssetBundle AB 加载的，如下所示。</p>
<ol>
<li>如果调用 AB.Unload(true) 。在活动场景中任何M的实例也将被卸载和销毁。</li>
<li>如果调用 ab.Unload（false） ，它将打破当前 M 和 AB 的联系。
<img src="/img/assetbundle/unloadfalse.png" alt="avatar">
如果 AB 再次被加载，并且 AB.LoadAsset（）被调用， Unity 不会将已经存在的使用 Material M 的实例与 AssetBundle AB 重新联系。因此将存在两份被加载的 Material M。
<img src="/img/assetbundle/after.jpg" alt="avatar">
通常，使用 assetbundle.Unload（false） 不会得到理想的情况。大多数项目都应该使用 assetbundle.Unload（true） 来避免在内存中复制对象。
大多数项目都应该使用 assetbundle.Unload（true） 并采用一种方法来确保对象不会被复制，两个常见的方法是:</li>
<li>在应用程序的生命周期中选择一个好的时机来卸载 AssetBundle ,比如关卡之间，或者加载场景的时候。</li>
<li>为每个对象采取引用计数管理方法，只有当 AssetBundle 的所有对象都没有被使用的时候，再卸载 AssetBundle。这样就可以避免应用出现重复对象的问题。
如果应用程序必须使用 assetbundle.Unload（false） ，那么单个对象只能以两种方式卸载：</li>
<li>在场景和代码中消除对不需要的对象的所有引用，然后调用 Resources.UnloadUnusedAssets();</li>
<li>加载一个没有额外附加的场景，这将消除当前场景的所有对象，并自动调用 Resources.UnloadUnusedAssets。
如果您不想自己管理加载 AssetBundle、依赖关系，以及资源，您可能会发现自己需要 AssetBundle 管理器。</li>
</ol>
</div>
                    <div class="post_footer">
                        
                        <div class="meta">
                            <div class="info">
                                <span class="field tags">
                                    <i class="ri-stack-line"></i>
                                    
                                    <a href="https://lenzan.github.io/tags/Unity3D/">Unity3D</a>
                                    
                                    <a href="https://lenzan.github.io/tags/AssetBundle/">AssetBundle</a>
                                    
                                </span>
                            </div>
                        </div>
                        
                    </div>
                </div>
                
                
            </div>
        </div>
    </div>
    <a id="back_to_top" href="#" class="back_to_top"><span>△</span></a>
    <footer class="footer">
    <div class="powered_by">
        <a href="https://varkai.com">Designed by VarKai,</a>
        <a href="http://www.gohugo.io/">Proudly published with Hugo</a>
    </div>

    <div class="footer_slogan">
        <span></span>
    </div>
</footer>
    <script src="https://lenzan.github.io/js/jquery-3.5.1.min.js"></script>
<link href="https://lenzan.github.io/css/fancybox.min.css" rel="stylesheet">
<script src="https://lenzan.github.io/js/fancybox.min.js"></script>
<script src="https://lenzan.github.io/js/zozo.js"></script>






</body>

</html>